#Importa os pacotes necessarios
import pygame, random, os

#Declara duas constantes
PLAYER = 1
CPU = 2

#Classe responsavel por manter as cells do tabuleiro
class Board:
	cells = None
	
	#Cria um tabuleiro vazio
	def __init__(self):
		self.cells = [[0,0,0],[0,0,0],[0,0,0]]		

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
		
#Classe que efetua uma tomada de decisao para o computador
class CPU:
	times = 0
	
	#Dado um tabuleiro desempenha uma acao
	def act(self,tab):
		play = False
		#Se jogou poucas vezes tenta uma abordagem aleatoria
		if self.times<=3:
			#Enquanto nao tiver uma jogada
			while(play!=True):
				#Escolha uma coordenada (i,j) aleatoriamente
				i = int(random.randint(0,2))
				j = int(random.randint(0,2))
				#Se a celula do tabuleiro estah vazia
				if tab.cells[i][j] == 0:
					#Define que o computador jogou
					play = True			
					#Marca a jogada no tabuleiro		
					tab.cells[i][j] = CPU
					#Incrementa sua jogada
					self.times = self.times + 1
		else:
			#Se jah existirem poucas celulas vazias
			#Procura a primeira celula vazia
			for i in range(3):
				for j in range(3):
					#Se estah vazia
					if tab.cells[i][j] == 0:
						#O computador joga
						play = True
						#Marca no tabuleiro a jogada do computador
						tab.cells[i][j] = CPU
						break						

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

#Classe responsavel pela manipulacao de som
class SoundManager:
	played = False

	#Efetua as inicializacoes e carrega os arquivos sonoros	
	def __init__(self):
		#Inicializacao do modulo mixer da SDL
		pygame.mixer.init()
		
		#carrega dois arquivos de som
		vader = os.path.join('data', 'vader.wav')
		yoda = os.path.join('data', 'yoda.wav')
		self.sndVader = pygame.mixer.Sound(vader)
		self.sndYoda = pygame.mixer.Sound(yoda)

	#Executa a musica de fundo
	def playMusic(self):		
		music = os.path.join('data','starwars.mid')
		pygame.mixer.music.load(music)  #Deixa music ativa
		pygame.mixer.music.play(-1)		#Executa em loop
    
	#Reproduz uma frase do Darth Vader
	def playDarthVader(self):
		self.sndVader.play()

	#Reproduz uma frase do Mestre Yoda
	def playYoda(self):
		self.sndYoda.play()
	
	#No final do jogo executa um som em funcao do vitorioso
	def play(self,w):
		#Se nao estah tocando nenhum som e tem um vitorioso
		if not self.played and w != 0:
			#Se o player venceu toca a frase do Mestre Yoda
			if w==PLAYER: self.playYoda()
			#Senao que venceu eh o Darth Vader
			elif w==CPU: self.playDarthVader()
			#Marca que estah tocando um som
			self.played = True

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
#Classe de visualizacao do estado do jogo				
class Renderer:
	sprPlayer = None	#Superficie da imagem do Yoda
	sprCPU = None		#Superficie da imagem do Darth Vader
	screen = None		#Superficie da tela principal
	sprTile = None		#Superficie referente ao chao
	
	#Efetua as inicializacoes e carrega recursos
	def __init__(self):
		pygame.init()			#Inicia a SDL
		pygame.font.init()		#Inicia a SDL_Font
		
		#Carrega umna imagem para icone
		icon = pygame.image.load(os.path.join('data',"icon.gif"))
		
		#Define as opcoes da janela ativa
		pygame.display.set_caption('TicTacWars')
		pygame.display.set_icon(icon)
		
		#Define uma janela com as dimensoes 144x144
		self.screen = pygame.display.set_mode((144,144))		
		
		#carrega todas as imagens
		self.sprPlayer = pygame.image.load(os.path.join('data',"yoda.gif"))
		
		self.sprCPU = pygame.image.load(os.path.join('data',"darth.gif"))
		
		self.sprTile = pygame.image.load(os.path.join('data',"tile.jpg"))
		
	#Efetua a pintura do estado do jogo considerando um tabuleiro
	#e se existe algum vencedor
	def paint(self,tab,w):
		#para cada celula do tabuleiro
		for i in range(3):
			for j in range(3):
				#Pinta o chao (fundo)
				self.screen.blit(self.sprTile, (i*48,j*48))
				#Se for uma jogada do player pinta Yoda na tela
				if tab.cells[i][j] == PLAYER:
					self.screen.blit(self.sprPlayer, (i*48,j*48))
				#Se for uma jogada do PC pinta Darth Vader na tela
				elif tab.cells[i][j] == CPU:
					self.screen.blit(self.sprCPU, (i*48,j*48))
				else:
					pass
		#Se existe vitorioso pinta a mensagem final
		if(w!=0): self.win(w)
		
		#Faz o flip, manda a imagem do framebuffer para o display
		pygame.display.flip()
		
	#Cria um texto centralizado na tela usando uma dada fonte
	def write(self,strs,font):
		#Cria o texto
		txt = font.render(strs,True,(255,0,0))
		#Centraliza		
		dim = txt.get_size()
		dimWin = self.screen.get_size()		
		x = (dimWin[0]/2)-(dim[0]/2)		
		y = (dimWin[1]/2)-(dim[1]/2)
		#Pinta a mensagem no centro da tela
		self.screen.blit(txt,(x,y))
		#Faz o flip, manda a imagem do framebuffer para o display
		pygame.display.flip()
	
	#Escreve mensagem na tela conforme o vitorioso			
	def win(self,w):
		#Obtem a fonte verdana
		verdana = pygame.font.match_font('Verdana')
		font = pygame.font.SysFont(verdana,32,True)
		#E manda escrever um texto conforme o vencedor
		if w == PLAYER: self.write('You win',font)			
		else: self.write('You lose',font)

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
#Responsavel pelo controle de todo o jogo
class GamePlay:
	done = True	
	tab = None
	#x,y = 0,0
	cpu = CPU()
	render = None
	sndManager = None
	playCPU = False
	winner = 0
	
	#Inicializa um tabuleiro (modelo), um render (visao)
	#e um gerenciador de som (visao)
	def __init__(self):
		self.tab = Board()
		self.render = Renderer()
		self.sndManager = SoundManager()			
		 
	#Obtem as entradas do mouse
	def getInputs(self):
		#Para cada evento na fila
		for event in pygame.event.get():
			#Se for de saida encerra a aplicacao
			if event.type == pygame.QUIT: 
				self.done = False
			#Se for um evento do mouse
			elif event.type == pygame.MOUSEBUTTONDOWN:
				#Se nao tem vencedor
				if self.winner==0:
					#Define a jogada do player
					pos = pygame.mouse.get_pos()				
					x = int(pos[0]/48)
					y = int(pos[1]/48)							
					self.tab.cells[x][y] = PLAYER
					self.playCPU = True
	
	#Verifica se tem vencedor
	def verifyWin(self):
		#Lines
		for i in range(3):
			if (self.tab.cells[i][0]==self.tab.cells[i][1])	and \
			(self.tab.cells[i][1]==self.tab.cells[i][2]): 
				if(self.tab.cells[i][0]!=0):
					self.winner = self.tab.cells[i][0] 
					return True
		
		#Cols
		for c in range(3):
			if (self.tab.cells[0][c]==self.tab.cells[1][c])	and \
			(self.tab.cells[1][c]==self.tab.cells[2][c]): 
				if(self.tab.cells[0][c]!=0):
					self.winner = self.tab.cells[0][c] 
					return True
			
		#Diagonais
		if (self.tab.cells[0][0]==self.tab.cells[1][1])	and \
		(self.tab.cells[1][1]==self.tab.cells[2][2]): 
			if(self.tab.cells[0][0]!=0):
				self.winner = self.tab.cells[0][0] 
				return True

		if (self.tab.cells[0][2]==self.tab.cells[1][1])	and \
		(self.tab.cells[1][1]==self.tab.cells[2][0]): 
			if(self.tab.cells[0][2]!=0):
				self.winner = self.tab.cells[0][2] 
				return True
	
	#Atualiza o estado do jogo						
	def update(self):
		#Se eh a vez do computador jogar
		if self.playCPU:
			#A CPU faz uma acao usando o tabuleiro atual
			self.cpu.act(self.tab)
			#Conclui a jogada
			self.playCPU = False
		#No final determina se alguem venceu ou perdeu
		self.verifyWin()
		
	#Pinta um novo frame da cena
	def paintScene(self):		
		#Solicita para o render efetuar esta tarefa
		self.render.paint(self.tab,self.winner)
		#Solicita para o gerenciador de som
		self.sndManager.play(self.winner)
		
	#LOOP PRINCIPAL!
	def gameLoop(self):
		clock = pygame.time.Clock()		#Para sincronizar
		self.sndManager.playMusic()		#Solicita para reproduzir musica

		#Enquanto nao for para parar
		while self.done:														
			self.getInputs()			#Pega as entradas do mouse
			self.update()				#Atualiza o mundo (cena)
			self.paintScene()			#Pinta um novo frame
			clock.tick(40)				#Sincroniza para manter 40fps
				
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
#Metodo principal de uma aplicao Python
def main(winstyle = 0):	
	rules = GamePlay()		#Cria um objeto gameplay
	rules.gameLoop()		#E comeca a execucao

#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
#Usado para definir qual eh o metodo main da aplicacao
if __name__ == "__main__":
    main()
    
#+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-